package org.example.module.security.auth;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.example.module.common.SysHttpStatus;
import org.example.module.security.JwtTokenUtil;
import org.example.module.security.SecuritySettings;
import org.example.module.utils.ResponseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
	
	private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationProcessingFilter.class);

	private SecuritySettings settings;
	
	private ObjectMapper mapper;
	
	@Autowired
	private JwtTokenUtil tokenFactory;

	@Autowired
	public JwtAuthenticationProcessingFilter(SecuritySettings settings, ObjectMapper objectMapper, RequestMatcher matcher) {
		super(matcher);
		this.settings = settings;
		this.mapper = objectMapper;
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		String tokenPayload = request.getHeader(settings.getTokenHeaderParam());
		if (StringUtils.isBlank(tokenPayload)) {
			throw new AuthenticationServiceException("认证失败！令牌不能为空！");
		}
		logger.info("token is {}", tokenPayload);
		return getAuthenticationManager().authenticate(new JwtAuthenticationToken(tokenPayload));
	}

	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
			Authentication authResult) throws IOException, ServletException {
		SecurityContext context = SecurityContextHolder.createEmptyContext();
		context.setAuthentication(authResult);
		SecurityContextHolder.setContext(context);
		chain.doFilter(request, response);
	}

	@Override
	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException e) throws IOException {
		SecurityContextHolder.clearContext();
		response.setStatus(HttpStatus.UNAUTHORIZED.value());
		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
		response.setCharacterEncoding("UTF-8");
		mapper.writeValue(response.getWriter(), ResponseUtils.error(SysHttpStatus.AUTH_EXCEPTION.getCode(),
				e.getMessage()));
	}
}
